#include "common.h"

int server = 0;
int port = 8000;
char hostname[32];

void server_routine();
void client_routine();
void* process(void*);
void sender(int);
void* mesure(void*);
void handler(int);

int g_nbytes = 0;

int main(int argc, char* argv[]) {
	int ret;
	pthread_t th;
	Args args = parsecmdline(argc, argv);
	if (args.empty() || args.find("h") == args.end()
			|| (args.find("l") != args.end() && args.find("p") != args.end())
			|| (args.find("l") == args.end() && args.find("p") == args.end())) {
		printf("Usage:\n  %s <-h hostname> <-p port or -l port>\n", argv[0]);
		return 1;
	}

  
	strcpy(hostname, args["h"].c_str());

	if (args.find("l") != args.end()) {
		port = atoi(args["l"].c_str());
		server = 1;
	}
	else {
		port = atoi(args["p"].c_str());
	}

	ret = pthread_create(&th, NULL, mesure, NULL);
	if (ret != 0) {
		errno = ret;
		ERR_EXIT("pthread_create");
	}

	if (SIG_ERR == signal(SIGPIPE, handler)) {
		ERR_EXIT("signal");
	}

	if (server) {
		server_routine();
	}
	else {
		client_routine();
	}
	return 0;
}

void server_routine() {
  int listenfd, clientfd, ret, len;
	int *fd;
	pthread_t th;
  struct sockaddr_in servaddr, cliaddr;
	socklen_t servaddrlen, cliaddrlen;

	servaddr = resolve(hostname, port);

	listenfd = socket(AF_INET, SOCK_STREAM, 0);
	if (listenfd < 0) ERR_EXIT("socket");

	ret  = bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
	if (ret < 0) ERR_EXIT("bind");

	ret = listen(listenfd, 5);
	if (ret < 0) ERR_EXIT("listen");

	while(1) {
		cliaddrlen = sizeof(cliaddr);
		clientfd = accept(listenfd, (struct sockaddr*)&cliaddr, &cliaddrlen);
		if (clientfd < 0) ERR_EXIT("accept");
		printf("%s:%d come in\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
		fd = (int*)malloc(sizeof(int));
		*fd = clientfd;
    ret = pthread_create(&th, NULL, process, (void*)fd);
		if (ret != 0) {
			free(fd);
			errno = ret;
			ERR_EXIT("pthread_create");
		}
	}
}

void client_routine() {
	int sockfd, ret, *fd;
  struct sockaddr_in servaddr;
	char *buf;
	pthread_t th;

	servaddr = resolve(hostname, port);
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd < 0) ERR_EXIT("socket");

	ret = connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
	if (ret < 0) ERR_EXIT("connect");
  
	sender(sockfd);
}

void* process(void *arg) {
	int sockfd, n, ret, *fd;
	char *buf;
	pthread_t th;

  sockfd = *(int*)arg;

	sender(sockfd);  

	free(arg);
}

void sender(int sockfd) {
  int i, nr, nw;
	char* buf;

  buf	= (char*)malloc(4096);;
  assert(buf);

	for (i = 0; i < 4096; ++i) {
		buf[i] = "0123456789ABCDEF"[i%16];
	}

	while(1) {
    nw = writen(sockfd, buf, 4096);
		if (nw < 0) break;
		__sync_fetch_and_add(&g_nbytes, nw);
	}

  shutdown(sockfd, SHUT_WR);

	free(buf);
	puts("Finish send");
}

void* mesure(void*) {
	int nbytes; 
	int64_t start, end;
	double elapsed;

  start	= now();

	while(1) {
		sleep(3);
    nbytes = __sync_lock_test_and_set(&g_nbytes, 0);
		end = now();
		elapsed = (end - start)/1000000.0;
		printf("%d bytes translate, %.3f MB/s\n", nbytes, 1.0*nbytes/1024/1024/elapsed);
		start = end;
	}
}

void handler(int sig) {
	if (sig == SIGPIPE) {
		puts("hello SIGPIPE");
	}
}
